<?php

declare(strict_types=1);

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer\Tests\Fixer\Phpdoc;

use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
use PhpCsFixer\WhitespacesFixerConfig;

/**
 * @internal
 *
 * @covers \PhpCsFixer\Fixer\Phpdoc\AlignMultilineCommentFixer
 *
 * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Phpdoc\AlignMultilineCommentFixer>
 *
 * @author Filippo Tessarotto <zoeslam@gmail.com>
 *
 * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\Phpdoc\AlignMultilineCommentFixer
 *
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
 */
final class AlignMultilineCommentFixerTest extends AbstractFixerTestCase
{
    public function testInvalidConfiguration(): void
    {
        $this->expectException(InvalidFixerConfigurationException::class);

        $this->fixer->configure(['a' => 1]);
    }

    /**
     * @param _AutogeneratedInputConfiguration $configuration
     *
     * @dataProvider provideFixCases
     */
    public function testFix(string $expected, ?string $input = null, array $configuration = [], bool $useTabsAndWindowsNewlines = false): void
    {
        if ($useTabsAndWindowsNewlines) {
            $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
        }
        $this->fixer->configure($configuration);
        $this->doTest($expected, $input);
    }

    /**
     * @return iterable<int, array{0: string, 1?: null|string, 2?: _AutogeneratedInputConfiguration, 3?: true}>
     */
    public static function provideFixCases(): iterable
    {
        foreach (self::getFixCases() as $case) {
            yield $case;

            yield [
                str_replace("\n", "\r\n", $case[0]),
                isset($case[1]) ? str_replace("\n", "\r\n", $case[1]) : null,
                $case[2] ?? [],
                true,
            ];
        }

        yield [
            '<?php
    /*
     * Doc-like Multiline comment
     *
     *
     */',
            '<?php
    /*
     * Doc-like Multiline comment
       *
*
   */',
            ['comment_type' => 'phpdocs_like'],
        ];

        yield [
            '<?php
    /*
     * Multiline comment with mixed content
       *
  Line without an asterisk
*
   */',
            null,
            ['comment_type' => 'phpdocs_like'],
        ];

        yield [
            '<?php
    /*
     * Two empty lines
        *


*
   */',
            null,
            ['comment_type' => 'phpdocs_like'],
        ];

        yield [
            '<?php
    /*
     * Multiline comment with mixed content
     *
  Line without an asterisk
     *
     */',
            '<?php
    /*
     * Multiline comment with mixed content
       *
  Line without an asterisk
*
   */',
            ['comment_type' => 'all_multiline'],
        ];
    }

    /**
     * @return iterable<array{0: string, 1?: string}>
     */
    private static function getFixCases(): iterable
    {
        yield [
            '<?php
$a = 1;
    /**
     * Doc comment
     *
     *
     *
     * first without an asterisk
     * second without an asterisk or space
     */',
            '<?php
$a = 1;
    /**
     * Doc comment
       *

*
    first without an asterisk
second without an asterisk or space
   */',
        ];

        yield [
            '<?php
    /**
     * Document start
     */',
            '<?php
    /**
* Document start
    */',
        ];

        yield [
            "<?php\n \n /**\n  * Two new lines\n  */",
            "<?php\n \n /**\n* Two new lines\n*/",
        ];

        yield [
            "<?php
\t/**
\t * Tabs as indentation
\t */",
            "<?php
\t/**
* Tabs as indentation
        */",
        ];

        yield [
            '<?php
$a = 1;
/**
 * Doc command without prior indentation
 */',
            '<?php
$a = 1;
/**
* Doc command without prior indentation
*/',
        ];

        yield [
            '<?php
/**
 * Doc command without prior indentation
 * Document start
 */',
            '<?php
/**
* Doc command without prior indentation
* Document start
*/',
        ];

        // Untouched cases
        yield [
            '<?php
    /*
     * Multiline comment
       *
*
   */',
        ];

        yield [
            '<?php
    /** inline doc comment */',
        ];

        yield [
            '<?php
 $a=1;  /**
*
 doc comment that doesn\'t start in a new line

*/',
        ];

        yield [
            '<?php
    # Hash single line comments are untouched
     #
   #
      #',
        ];

        yield [
            '<?php
    // Slash single line comments are untouched
     //
   //
      //',
        ];

        yield 'uni code test' => [
            '<?php
class A
{
    /**
     * @SWG\Get(
     *     path="/api/v0/cards",
     *     operationId="listCards",
     *     tags={"Банковские карты"},
     *     summary="Возвращает список банковских карт."
     *  )
     */
    public function indexAction()
    {
    }
}',
        ];
    }
}
